//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================


using System;
using Shp.Runtime.Sitka.ServiceAgent.Managers;
using Shp.Runtime.Sitka.ServiceAgent;
using Shp.Runtime.Sitka.ServiceAgent.Entities;
using Shp.Runtime.Sitka.ServiceAgent.EntityMappers;
using System.Collections.ObjectModel;
using Shp.Runtime.Common;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Xml.Linq;
using System.Linq;


namespace LitwareHR.Portfolio.DataModel.Sitka
{
	public class ProvisioningDataModel
	{
		private IRepositoryFactory repositoryFactory;

		public ProvisioningDataModel(IRepositoryFactory factory)
		{
			repositoryFactory = factory;
		}

		public ProvisioningDataModel()
		{
			repositoryFactory = new GenericRepositoryFactory();
		}

        private static void AddAuthorization(string actionId, Guid tenantId, string credential, Repository<GenericExtensibleEntity> repository)
        {
            GenericExtensibleEntity authorization = new GenericExtensibleEntity(Constants.EntityKinds.AuthorizationKind, Guid.NewGuid());
            authorization.Fields.Add(new Field(Constants.EntityFields.TenantIdField, tenantId.ToString()));
            authorization.Fields.Add(new Field(Constants.EntityFields.ActionIdField, actionId));
            authorization.Fields.Add(new Field(Constants.EntityFields.CredentialField, credential));

            repository.Insert(authorization);
        }
                    
        private static void AuthorizationProvisioning(Guid tenantId, Repository<GenericExtensibleEntity> repository)
        {
            //runtime
            foreach (string action in Constants.ActionIds.ProvisioningRuntimeActionsAdministrator)
            {
                AddAuthorization(action, tenantId, Constants.EntityFieldValues.CredentialAdministrator, repository);
            }

            foreach (string action in Constants.ActionIds.ProvisioningRuntimeActionsApplyForAJob)
            {
                AddAuthorization(action, tenantId, Constants.EntityFieldValues.CredentialApplyForAJob, repository);
            }

            foreach (string action in Constants.ActionIds.ProvisioningRuntimeActionsConfigureAndCustomize)
            {
                AddAuthorization(action, tenantId, Constants.EntityFieldValues.CredentialConfigureAndCustomize, repository);
            }

            foreach (string action in Constants.ActionIds.ProvisioningRuntimeActionsEvaluateCandidate)
            {
                AddAuthorization(action, tenantId, Constants.EntityFieldValues.CredentialEvaluateCandidate, repository);
            }

            foreach (string action in Constants.ActionIds.ProvisioningRuntimeActionsManageUsersAndRoles )
            {
                AddAuthorization(action, tenantId, Constants.EntityFieldValues.CredentialManageUsersAndRoles, repository);
            }

            foreach (string action in Constants.ActionIds.ProvisioningRuntimeActionsOpenPosition)
            {
                AddAuthorization(action, tenantId, Constants.EntityFieldValues.CredentialOpenPosition, repository);
            }

            //recruiting
            foreach (string action in Constants.ActionIds.ProvisioningRecruiting)
            {
                AddAuthorization(action, tenantId, Constants.EntityFieldValues.CredentialAdministrator, repository);
            }            
        }

		public void PerformModulesProvisioning(Guid tenantId, string tenantName, string tenantAlias, Guid workflowShortId, Guid workflowLongId)
		{
			using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
			{
				//insert default style
				GenericExtensibleEntity styleInstance = GetDefaultStyleEntity(tenantId);
				repository.Insert(styleInstance);

				//insert tenant metadata
				GenericExtensibleEntity tenantInstance = new GenericExtensibleEntity(Constants.EntityKinds.TenantEntityKind, tenantId);
				tenantInstance.Fields.Add(new Field(Constants.EntityFields.GenericNameField, tenantName));
				tenantInstance.Fields.Add(new Field(Constants.EntityFields.TenantAliasField, tenantAlias));
				tenantInstance.Fields.Add(new Field(Constants.EntityFields.TenantStyleField, styleInstance.Id.ToString()));
				tenantInstance.Fields.Add(new Field(Constants.EntityFields.TenantLayoutField, Constants.EntityFieldValues.TenantLayoutDefault));

				repository.Insert(tenantInstance);

				//insert position default fields
				Collection<GenericExtensibleEntity> positionFields = GetDefaultPosition(tenantId.ToString(), Constants.EntityFieldValues.PositionId);
				foreach (GenericExtensibleEntity field in positionFields)
				{
					repository.Insert(field);
				}

                //insert authorizations
                AuthorizationProvisioning(tenantId, repository);

				//insert workflow default definition.				
				InsertWorkflowDefault(workflowShortId, repository, Constants.Workflow.ShortWorkflowDefinition, Constants.EntityFieldValues.WorkflowShortName, tenantId);
				InsertWorkflowDefault(workflowLongId, repository, Constants.Workflow.LongWorkflowDefinition, Constants.EntityFieldValues.WorkflowLongName, tenantId);

				//insert ruleset
				InsertRuleSetDefault(tenantId, repository, workflowLongId, workflowShortId);
				
				//insert MainMenu				
				InsertMainMenuDefault(tenantId, tenantAlias, repository);
		
			}

			ContainerManager.CreateContainer(tenantId.ToString());
		}

		private static void InsertMainMenuDefault(Guid tenantId, string tenantAlias, Repository<GenericExtensibleEntity> repository)
		{
			Stream menuStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(Constants.Presentation.MainMenuXml);
			XDocument xDocument;
			using (StreamReader reader = new StreamReader(menuStream))
			{
				xDocument = XDocument.Load(reader);
			}

			var query = from e in xDocument.Element("Menus").Elements("mainmenu")
							select new
							{
								Description = (string)e.Attribute("description"),
								IsPublic = (bool)e.Attribute("isPublic"),
								Ordinal = (int)e.Attribute("ordinal"),
								UrlFormat = (string)e.Attribute("uri")
							};
				foreach (var item in query)
				{
					GenericExtensibleEntity mainMenu = new GenericExtensibleEntity("MainMenu", Guid.NewGuid());
					mainMenu.Fields.Add(new Field("TenantId", tenantId.ToString()));
					mainMenu.Fields.Add(new Field("Description", item.Description));
					mainMenu.Fields.Add(new Field("IsPublic", item.IsPublic));
					mainMenu.Fields.Add(new Field("Ordinal", item.Ordinal.ToString(CultureInfo.InvariantCulture)));
					string url = string.Empty;
					switch (item.Description.Trim())
					{
						case "Careers":
						case "Configuration and Customization":
							url = item.UrlFormat;
							break;
						default:
							url = string.Format(CultureInfo.InvariantCulture,item.UrlFormat, tenantAlias);
							break;
					}
					mainMenu.Fields.Add(new Field("Url", url));
					repository.Insert(mainMenu);
				}

			
		}

		private static void InsertRuleSetDefault(Guid tenantId, Repository<GenericExtensibleEntity> repository, Guid workflowLongId, Guid workflowShortId)
		{
			Stream ruleSetStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(Constants.Workflow.RuleSetDefinition);
			string xomlRuleSet = String.Empty;
			using (StreamReader reader = new StreamReader(ruleSetStream))
			{
				xomlRuleSet = reader.ReadToEnd();
			}

            //xomlRuleSet = String.Format(CultureInfo.InvariantCulture, xomlRuleSet, workflowLongId, workflowShortId);
            xomlRuleSet = xomlRuleSet.Replace("{0}", workflowLongId.ToString()).Replace("{1}", workflowShortId.ToString());

			GenericExtensibleEntity ruleSetEntity = new GenericExtensibleEntity(Constants.EntityKinds.RuleSetEntityKind, Guid.NewGuid());
			ruleSetEntity.Fields.Add(new Field(Constants.EntityFields.TenantIdField, tenantId.ToString()));
			ruleSetEntity.Fields.Add(new Field(Constants.EntityFields.RuleSetMarkupField, xomlRuleSet));

			repository.Insert(ruleSetEntity);			
		}

		private static void InsertWorkflowDefault(Guid workflowId, Repository<GenericExtensibleEntity> repository, string workflowDefFile, string workflowName, Guid tenandId)
		{
			Stream shortWorkflowStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(workflowDefFile);
			string xomlWorkflow = string.Empty;
			using (StreamReader reader = new StreamReader(shortWorkflowStream))
			{
				xomlWorkflow = reader.ReadToEnd();
			}

			GenericExtensibleEntity tenantWorkflowDef = new GenericExtensibleEntity(Constants.EntityKinds.WorkflowEntityKind, workflowId);
			tenantWorkflowDef.Fields.Add(new Field(Constants.EntityFields.TenantIdField,tenandId.ToString()));
			tenantWorkflowDef.Fields.Add(new Field(Constants.EntityFields.WorkflowNameField, workflowName));
			tenantWorkflowDef.Fields.Add(new Field(Constants.EntityFields.WorkflowXomlField, xomlWorkflow));

			repository.Insert(tenantWorkflowDef);
		}


		public void ProvisionSilverlightStreaming(Guid tenantId, string silverlightAccountId, string silverlightAccountKey)
		{
			using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
			{
				GenericExtensibleEntity tenantInstance = repository.GetById(tenantId);
				if (tenantInstance != null)
				{
					tenantInstance.Fields.Add(new Field(Constants.EntityFields.TenantSilverlightAccountIdField, silverlightAccountId));
					tenantInstance.Fields.Add(new Field(Constants.EntityFields.TenantSilverlightAccountKeyField, silverlightAccountKey));

					repository.Update(tenantInstance);
				}
			}
		}

		private Collection<GenericExtensibleEntity> GetDefaultPosition(string tenantId, string entityDefId)
		{
			Collection<GenericExtensibleEntity> fields = new Collection<GenericExtensibleEntity>();

			GenericExtensibleEntity codeField = new GenericExtensibleEntity(Constants.EntityKinds.EntityDefFieldKind, Guid.NewGuid());
			codeField.Fields.Add(new Field("EntityDefId", entityDefId));
			codeField.Fields.Add(new Field(Constants.EntityFields.GenericNameField, "code"));
			codeField.Fields.Add(new Field("TypeId", "fa564e7c-f59b-480f-a768-a1d02a34e32c"));
			codeField.Fields.Add(new Field("IsShared", true));
			codeField.Fields.Add(new Field(Constants.EntityFields.TenantIdField, tenantId));
			fields.Add(codeField);
			fields.Add(GetViewField(codeField, 0, Constants.EntityFieldValues.JobSearchViewId));
			fields.Add(GetViewField(codeField, 0, Constants.EntityFieldValues.JobDetailViewId));

			GenericExtensibleEntity postedOnField = new GenericExtensibleEntity(Constants.EntityKinds.EntityDefFieldKind, Guid.NewGuid());
			postedOnField.Fields.Add(new Field("EntityDefId", entityDefId));
			postedOnField.Fields.Add(new Field(Constants.EntityFields.GenericNameField, "postedOn"));
			postedOnField.Fields.Add(new Field("TypeId", "018d42ba-ca23-4e15-9c01-e941c86dd36f"));
			postedOnField.Fields.Add(new Field("IsShared", true));
			postedOnField.Fields.Add(new Field(Constants.EntityFields.TenantIdField, tenantId));
			fields.Add(postedOnField);
			fields.Add(GetViewField(postedOnField, 1, Constants.EntityFieldValues.JobSearchViewId));
			fields.Add(GetViewField(postedOnField, 1, Constants.EntityFieldValues.JobDetailViewId));

			GenericExtensibleEntity titleField = new GenericExtensibleEntity(Constants.EntityKinds.EntityDefFieldKind, Guid.NewGuid());
			titleField.Fields.Add(new Field("EntityDefId", entityDefId));
			titleField.Fields.Add(new Field(Constants.EntityFields.GenericNameField, "title"));
			titleField.Fields.Add(new Field("TypeId", "b44a04ca-3426-4c8d-9fc0-431de22d6f4e"));
			titleField.Fields.Add(new Field("IsShared", true));
			titleField.Fields.Add(new Field(Constants.EntityFields.TenantIdField, tenantId));
			fields.Add(titleField);
			fields.Add(GetViewField(titleField, 2, Constants.EntityFieldValues.JobSearchViewId));
			fields.Add(GetViewField(titleField, 2, Constants.EntityFieldValues.JobDetailViewId));

			GenericExtensibleEntity locationField = new GenericExtensibleEntity(Constants.EntityKinds.EntityDefFieldKind, Guid.NewGuid());
			locationField.Fields.Add(new Field("EntityDefId", entityDefId));
			locationField.Fields.Add(new Field(Constants.EntityFields.GenericNameField, "location"));
			locationField.Fields.Add(new Field("TypeId", "b44a04ca-3426-4c8d-9fc0-431de22d6f4e"));
			locationField.Fields.Add(new Field("IsShared", false));
			locationField.Fields.Add(new Field(Constants.EntityFields.TenantIdField, tenantId));
			fields.Add(locationField);
			fields.Add(GetViewField(locationField, 3, Constants.EntityFieldValues.JobSearchViewId));
			fields.Add(GetViewField(locationField, 3, Constants.EntityFieldValues.JobDetailViewId));

			return fields;

		}


		private GenericExtensibleEntity GetViewField(GenericExtensibleEntity entityField, int ordinal, string viewDefId)
		{

			GenericExtensibleEntity field = new GenericExtensibleEntity(Constants.EntityKinds.ViewDefFieldKind, Guid.NewGuid());
			field.Fields.Add(new Field("ViewDefId", viewDefId));
			field.Fields.Add(new Field(Constants.EntityFields.GenericNameField, entityField.GetFieldValue(Constants.EntityFields.GenericNameField)));
			field.Fields.Add(new Field("Label", entityField.GetFieldValue(Constants.EntityFields.GenericNameField)));
			field.Fields.Add(new Field("Ordinal", ordinal.ToString(CultureInfo.InvariantCulture)));
			field.Fields.Add(new Field(Constants.EntityFields.TenantIdField, entityField.GetFieldValue(Constants.EntityFields.TenantIdField)));

			return field;

		}

		private GenericExtensibleEntity GetDefaultStyleEntity(Guid tenantId)
		{
			string name = "litware";
			string url = "http://www.litware.com/Css/default.css";

			GenericExtensibleEntity extensibleEntity = new GenericExtensibleEntity(Constants.EntityKinds.StyleKind, Guid.NewGuid());

			Field field = new Field(Constants.EntityFields.TenantIdField, tenantId.ToString());
			extensibleEntity.Fields.Add(field);

			field = new Field(Constants.EntityFields.GenericNameField, name);
			extensibleEntity.Fields.Add(field);

			field = new Field("Url", url);
			extensibleEntity.Fields.Add(field);

			return extensibleEntity;
		}

	}
}
